package ru.compscicenter.databases.zaikina.common;

import ru.compscicenter.databases.zaikina.common.commands.SysCommand;
import ru.compscicenter.databases.zaikina.common.commands.SysCommandBuffer;
import ru.compscicenter.databases.zaikina.common.commands.SysCommandType;

import java.util.ArrayList;

public class DatabaseManager implements Runnable {

    private ManagedObject managedObj;
    private ManagedObject managedObjCopy;

    private SysCommandBuffer buffer;

    private Boolean isReady = false;
    private final ManagerEventListener listener;

    public DatabaseManager(ManagedObject managedObject, ManagerEventListener listener) {
        this.managedObj = managedObject;
        this.listener = listener;
        this.buffer = new SysCommandBuffer(this.managedObj.getNodeId());
        this.buffer.loadCommands();
    }

    public SysCommandBuffer setBuffer(SysCommandBuffer buff) {
        synchronized (this) {
            if (buffer.isEmpty()) {
                SysCommandBuffer remember = buffer;
                buffer = buff;
                return remember;
            }
        }
        return buff;
    }

    public void run() {
        while (true) {
            boolean flag = buffer.isEmpty();

            if (!flag) {
                for (SysCommand<?, ?> command : buffer.value()) {
                    System.out.println("Process difficult command: " + command.toJSONString());
                    managedObj.process(command);
                    sendNotifications();
                }
                managedObj.commit();
                buffer.clear();
            } else {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    break;
                }
            }
        }
    }

    private void sendNotifications() {
        managedObjCopy = managedObj.clone();
        synchronized (this) {
            isReady = true;
        }
        listener.onReady(new ManagerEventImpl());
        synchronized (this) {
            isReady = false;
        }
    }


    private class ManagerEventImpl implements ManagerEvent {

        public ManagedObject getUpdatedData(ManagedObject oldData) {
            boolean flag;
            synchronized (this) {
                flag = isReady;
            }

            if (flag) {
                ManagedObject newData;
                synchronized (this) {
                    newData = managedObjCopy;
                    managedObjCopy = oldData;
                }
                return newData;
            }
            return oldData;
        }
    }
}
